/************************************************************************
 * The code is owned by mainframer.cn and Shang Tao
 * Without aproval of mainframer.cn and Shang Tao, removing the copyright
 * infomation is regarded as invassion of proprietary copyright
 ***********************************************************************/
package com.mr.qa.servlet;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;
import org.hibernate.Transaction;

import com.mr.qa.GlobalConfigs;
import com.mr.qa.SpendMoneyConstants;
import com.mr.qa.UserSession;
import com.mr.qa.UserSessionUtil;
import com.mr.qa.GlobalConfigs.UploadFileType;
import com.mr.qa.action.check.DailyCheck;
import com.mr.qa.action.check.DailyDownloadSharedFileCheck;
import com.mr.qa.bo.SharedFile;
import com.mr.qa.bo.User;
import com.mr.qa.dao.impl.SharedFileDAO;
import com.mr.qa.dao.impl.UserDAO;
import com.mr.qa.util.HibernateSessionFactory;



public class DownloadFileServlet extends HttpServlet
{
    private static final Log logger = LogFactory.getLog(DownloadFileServlet.class);

    public void init(ServletConfig config) throws ServletException
    {
        super.init(config);
        
    }

    public void doGet(HttpServletRequest request, 
                      HttpServletResponse response) throws ServletException, 
                                                           IOException
    {
        doPost(request,response);
    }

    public void doPost(HttpServletRequest request, 
                       HttpServletResponse response) throws ServletException, 
                                                            IOException
    {
        String uri = request.getRequestURI();
        if(uri != null)
        {
            if(uri.indexOf(GlobalConfigs.SHAREDFILE_DIR) >= 0)
            {
                UserSession us = UserSessionUtil.getUserSession(request);
                //logger.info("user logined?"+(us == null));
                if(us != null)
                {
                    downSharedFile(request,response,us);
                }
                else
                {
                    //logger.info("goToLoginPage");
                    goToLoginPage(request,response);
                }
            }
            else if(uri.indexOf(UploadFileType.getPhysicalPath(UploadFileType.attachment)) >= 0)
            {
                downUploadedFile(request,response);
            }
            else
            {
                downTestFile(request,response);
            }
        }
    }
    
    private void downTestFile(HttpServletRequest request, 
                       HttpServletResponse response) throws ServletException, 
                                                            IOException
    {
        String phisicalFileRootDir = GlobalConfigs.WEB_PHISICAL_ROOT_LOCATION;
        String uri = request.getRequestURI();
        uri = URLDecoder.decode(uri,"UTF-8");        
        String fileName = uri.substring(uri.lastIndexOf("/")+1);
        //uri = Utf8URLdecode(uri);
        String pathSeparator = File.separator;
        String realFilePath = uri.replace(request.getContextPath()+"/test","");
        realFilePath = realFilePath.replace("/",pathSeparator);
        String phisicalFileName = phisicalFileRootDir+
        "test"+realFilePath;
        File file = new File(phisicalFileName);
        if(file.exists() && file.isFile())
        {
            FileInputStream fin = new FileInputStream(file);
            response.setContentType("application/octet-stream");//application/x-msdownload
            response.setHeader("Content-Disposition","attachment;filename="+fileName);
            byte[] bytes = new byte[2048];
            int lenPerRead;
            OutputStream os = response.getOutputStream();
            while((lenPerRead = fin.read(bytes)) != -1)
            {   
                 os.write(bytes,0,lenPerRead);   
            }
            fin.close();
            os.flush();
            os.close();
        }
        else
        {
            noFile(request,response);
        }
    }



    private void downUploadedFile(HttpServletRequest request, 
                       HttpServletResponse response) throws ServletException, 
                                                            IOException
    {
        String phisicalFileRootDir = GlobalConfigs.WEB_PHISICAL_ROOT_LOCATION;
        String uri = request.getRequestURI();
        String fileName = uri.substring(uri.lastIndexOf("/")+1);
        //uri = Utf8URLdecode(uri);
         uri = URLDecoder.decode(uri,"UTF-8");
        String pathSeparator = File.separator;
        String realFilePath = uri.replace(request.getContextPath()+"/"+UploadFileType.getPhysicalPath(UploadFileType.attachment),"");
        realFilePath = realFilePath.replace("/",pathSeparator);
        /*
        if(realFilePath.indexOf("%20") >= 0)
            realFilePath = realFilePath.replaceAll("%20"," ");
            */
        String phisicalFileName = phisicalFileRootDir+
        UploadFileType.getPhysicalPath(UploadFileType.attachment)+realFilePath;

        /*        
        String phisicalFileName = phisicalFileDir+File.separator+fileName;
        */
        File file = new File(phisicalFileName);
        //logger.info("uploaded phisicalFileName="+phisicalFileName+",exist?"+file.exists());
        if(file.exists() && file.isFile())
        {
            FileInputStream fin = new FileInputStream(file);
            
            response.setContentType("application/octet-stream");//application/x-msdownload
            //new String(textFileName.getBytes(),"GBK")
            //new String(textFileName.getBytes("GB2312"),"ISO8859-1")
            response.setHeader("Content-Disposition","attachment;filename="+fileName);
            byte[] bytes = new byte[2048];
            int lenPerRead;
            OutputStream os = response.getOutputStream();
            while((lenPerRead = fin.read(bytes)) != -1)
            {   
                 os.write(bytes,0,lenPerRead);   
            }
            fin.close();
            os.flush();
            os.close();
        }
        else
        {
            noFile(request,response);
        }
    }
    /**
     * 
     * @param request
     * @param response
     * @param us
     * @throws ServletException
     * @throws IOException
     */
    private void downSharedFile(HttpServletRequest request, 
                       HttpServletResponse response,UserSession us) throws ServletException, 
                                                            IOException
    {
        String phisicalFileRootDir = GlobalConfigs.WEB_PHISICAL_ROOT_LOCATION;
        String uri = request.getRequestURI();
        String fileName = uri.substring(uri.lastIndexOf("/")+1);
        //uri = Utf8URLdecode(uri);        
        uri = URLDecoder.decode(uri,"UTF-8");
        String pathSeparator = File.separator;
        if(pathSeparator.equals("\\"))
        {
            pathSeparator = "/";
        }
        String realFilePath = uri.replace(request.getContextPath()+"/"+GlobalConfigs.SHAREDFILE_DIR,"");
        //logger.info("realFilePath1="+realFilePath);
        realFilePath = realFilePath.replace("/",pathSeparator);
        //logger.info("realFilePath2="+realFilePath);
        String phisicalFileName = phisicalFileRootDir+
        GlobalConfigs.SHAREDFILE_DIR+realFilePath;
        
        //logger.info("file:"+phisicalFileName);
        
        File file = new File(phisicalFileName);
        if(file.exists() && file.isFile())
        {
            addDownloadCountForSharedFile(realFilePath,us);
            FileInputStream fin = new FileInputStream(file);
            response.setContentType("application/octet-stream");//application/x-msdownload
            response.setHeader("Content-Disposition","attachment;filename="+fileName);//gb2312Nam
            byte[] bytes = new byte[2048];
            int lenPerRead;
            OutputStream os = response.getOutputStream();
            while((lenPerRead = fin.read(bytes)) != -1)
            {   
                 os.write(bytes,0,lenPerRead);   
            }
            fin.close();
            os.flush();
            os.close();
            
            DailyCheck dailyCheck = new DailyDownloadSharedFileCheck();
            dailyCheck.update(us.getUserId());
        }
        else
        {
            logger.error("no test file:"+phisicalFileName);    
            noFile(request,response);
        }
    }





    private void goToLoginPage(HttpServletRequest request,HttpServletResponse response) throws ServletException, 
                                                                IOException
    {
        ActionMessages errors = new ActionMessages();
        errors.add("",new ActionMessage("login.required"));
        request.setAttribute("org.apache.struts.Globals.ERROR_KEY",errors);
        try
        {
            /*
            String filePath = request.getRequestURI();
            filePath = filePath.replace(request.getContextPath()+"/"+GlobalConfigs.SHAREDFILE_DIR,"");
            */
             String uri = request.getRequestURI();
             uri = URLDecoder.decode(uri,"UTF-8");
             String pathSeparator = File.separator;
             if(pathSeparator.equals("\\"))
             {
                 pathSeparator = "/";
             }
             String realFilePath = uri.replace(request.getContextPath()+"/"+GlobalConfigs.SHAREDFILE_DIR,"");
             //logger.info("realFilePath1="+realFilePath);
             realFilePath = realFilePath.replace("/",pathSeparator);
            //logger.info("filePath="+realFilePath);
            /*
            if(filePath != null && filePath.length() > 0)//&& filePath.indexOf("_") > 0 
            {
                String[] ls = filePath.split("_");
                if(ls.length == 3)
                {
                    String sharedFileIdStr = ls[1];
                    String forwardPath = null;
                    forwardPath = "/sf.mrqa?action=view&id="+sharedFileIdStr;
                    request.setAttribute("originalUrl",forwardPath);
                }
            }*/
            String forwardPath = null;
            String sharedFileId = this.getShareFileId(realFilePath);
            forwardPath = "/sf.mrqa?action=view&id="+sharedFileId;
            request.setAttribute("originalUrl",forwardPath);
        }
        catch(Exception e){}
        this.getServletConfig().getServletContext().getRequestDispatcher("/userlogin.mrqa").forward(request,response);
    }
    
    
    private void noFile(HttpServletRequest request,HttpServletResponse response)
    throws ServletException,IOException
    {
        this.getServletConfig().getServletContext().getRequestDispatcher("/nosharedfile.mrqa").forward(request,response);
    }
    
    /**
     * get the id of sharedfile by file path
     * @param filePath
     * @return
     */
    private String getShareFileId(String filePath)
    {
        Transaction tx = null;
        try
        {
            SharedFileDAO sharedFileDAO = new SharedFileDAO();
            sharedFileDAO.setPage(1,1);
            tx = HibernateSessionFactory.getSession().beginTransaction();
            SharedFile sf = sharedFileDAO.findByFilePath(filePath);
            tx.commit();
            if(sf == null)return null;
            else return sf.getId()+"";
        }
        catch(Exception e)
        {
            logger.error("get shared file id by file path:"+filePath+",exception:"+e);
            //if(tx != null)tx.rollback();
        }
        finally
        {
            HibernateSessionFactory.closeSession();  
        }
        return null;
    }
    
    /**
     * getting id of sharedfile by file path, then increase download count by 1
     * @param filePath
     */
    private void addDownloadCountForSharedFile(String filePath, UserSession us) {
		// logger.info("down file:"+filePath);
		Transaction tx = null;
		try {
			SharedFileDAO sharedFileDAO = new SharedFileDAO();
			sharedFileDAO.setPage(1, 1);
			tx = HibernateSessionFactory.getSession().beginTransaction();
			SharedFile sf = sharedFileDAO.findByFilePath(filePath);
			if (sf == null)
				return;
			sf.setDownloadCount(sf.getDownloadCount() + 1);
			sharedFileDAO.modify(sf);
			// not touch score when the author downloads self his/her file.
			// if(sf.getMrIaskUser().getId() != us.getUserId())
			// {
			/*
			 * sharedFileDAO.addScoreHistory(us.getUserId(),sf.getId(),
			 * "downloadsharedfile","downloading sharedfile:"+sf.getName());
			 */
			/*sharedFileDAO.addScoreHistory(sf.getMrIaskUser(), sf.getId(), sf
					.getName(), "addtosharedfileauthor",
					"get schore from other downloading sharedfile:"
							+ sf.getName());*/

			if (!sf.getMrIaskUser().getId().equals(us.getUserId())) {
				UserDAO userDAO = new UserDAO();
				User user = userDAO.findById(us.getUserId());
				sharedFileDAO.spendMoney(user, sf.getId(), sf.getName(),
						"downloadSharedFile", "" + SpendMoneyConstants.sharedFile);
			}

			// }
			tx.commit();
		} catch (Exception e) {
			logger.error("downloading sharedfile exception:" + e);
			if (tx != null)
				tx.rollback();
		} finally {
			HibernateSessionFactory.closeSession();
		}
	}
    
    //================do not touch the below methods======
    private String toUtf8String(String s) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < s.length(); i++) {
          char c = s.charAt(i);
          if (c >= 0 && c <= 255) {
            sb.append(c);
          }
          else {
            byte[] b;
            try {
              b = Character.toString(c).getBytes("utf-8");
            }
            catch (Exception ex) {
              System.out.println(ex);
              b = new byte[0];
            }
            for (int j = 0; j < b.length; j++) {
              int k = b[j];
              if (k < 0) {
                k += 256;
              }
              sb.append("%" + Integer.toHexString(k).toUpperCase());
            }
          }
        }
        return sb.toString();
      }


    /**
       * Utf8URL??
       * @param text
       * @return
       */
      public String Utf8URLdecode(String text) {
        String result = "";
        int p = 0;

        if (text!=null && text.length()>0){
          //text = text.toLowerCase();//?
          p = text.indexOf("%E");
          if(p == -1)
          {
              p = text.indexOf("%e");
          }
          if (p == -1)
          {
            return text;
          }

          while (p != -1) 
          {
            result += text.substring(0, p);
            text = text.substring(p, text.length());
            if (text == "" || text.length() < 9) return result;

            result += CodeToWord(text.substring(0, 9));
            text = text.substring(9, text.length());
            p = text.indexOf("%E");
            if(p == -1)
            {
                p = text.indexOf("%e");
            }
          }
        }
        return result + text;
      }
    
    /**
      * utf8URL?????
      * @param text
      * @return
      */
     private String CodeToWord(String text) {
       String result;
       text = text.toLowerCase();//newly added
       if (Utf8codeCheck(text)) {
         byte[] code = new byte[3];
         code[0] = (byte) (Integer.parseInt(text.substring(1, 3), 16) - 256);
         code[1] = (byte) (Integer.parseInt(text.substring(4, 6), 16) - 256);
         code[2] = (byte) (Integer.parseInt(text.substring(7, 9), 16) - 256);
         try {
           result = new String(code, "UTF-8");
         }catch (UnsupportedEncodingException ex) {
           result = null;
         }
       }
       else {
         result = text;
       }

       return result;
     }

    /**
       * ??????
       * @param text
       * @return
       */
      private boolean Utf8codeCheck(String text){
        String sign = "";
        text = text.toLowerCase();//newly added
        if (text.startsWith("%e"))
          for (int i = 0, p = 0; p != -1; i++) {
            p = text.indexOf("%", p);
            if (p != -1)
              p++;
            sign += p;
          }
        return sign.equals("147-1");
      }


}
